{
  description = ''
    2024 傲来操作系统（EulixOS）训练营在线作业
  '';

  nixConfig = {
    experimental-features = [
      "flakes"
      "nix-command"
    ];

    extra-substituters = [ "https://nix-community.cachix.org" ];

    extra-trusted-public-keys = [
      "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
    ];

    substituters = [
      "https://mirror.iscas.ac.cn/nix-channels/store"
      "https://cache.nixos.org/"
    ];
  };

  # Nix packages
  inputs = {
    nixpkgs = {
      follows = "nixpkgs-unstable";
    };
    nixpkgs-stable = {
      url = "github:NixOS/nixpkgs/nixos-23.11";
    };
    nixpkgs-unstable = {
      url = "github:NixOS/nixpkgs/nixos-unstable";
    };
  };

  # Nix libraries
  inputs = {
    flake-compat = {
      url = "github:edolstra/flake-compat/master";
      flake = false;
    };
    flake-utils = {
      url = "github:numtide/flake-utils/main";
      inputs = {
        systems = {
          follows = "nix-systems";
        };
      };
    };
    nix-systems = {
      url = "github:nix-systems/default-linux/main";
    };
    treefmt = {
      url = "github:numtide/treefmt-nix/main";
      inputs = {
        nixpkgs = {
          follows = "nixpkgs";
        };
      };
    };
  };

  outputs =
    {
      flake-utils,
      nix-systems,
      nixpkgs,
      self,
      treefmt,
      ...
    }@inputs:
    let
      inherit (nixpkgs.lib) genAttrs;

      lib = nixpkgs.lib // builtins;

      systems = (import nix-systems) ++ [ "riscv64-linux" ];
    in
    flake-utils.lib.eachSystem systems (
      system:
      let
        pkgs = import nixpkgs { inherit system; };

        pkgsWithCrossRISCV64 = import nixpkgs {
          inherit system;

          crossSystem = {
            config = "riscv64-unknown-linux-gnu";
          };
        };

        pkgsCrossRISCV64 = pkgsWithCrossRISCV64.pkgsCross.riscv64;

        pkgsNativeRISCV64 = {
          system = "riscv64-linux";
        };

        treefmt' = treefmt.lib.evalModule pkgs {
          projectRootFile = "flake.nix";

          programs = {
            clang-format = {
              enable = true;
              package = pkgs.clang-tools;
            };

            nixfmt = {
              enable = true;
              package = pkgs.nixfmt-rfc-style;
            };

            shfmt = {
              enable = true;
            };
          };
        };
      in
      {
        checks = {
          formatting = treefmt'.config.build.check self;
        };

        devShells = {
          default = pkgs.mkShell rec {
            buildInputs = nativeBuildInputs;

            nativeBuildInputs =
              (with pkgs; [
                # Shell
                fish

                # Build tools
                cmake
                gnumake
              ])
              ++ (with pkgsCrossRISCV64; [
                # Tools
                # NOTE clang-tools must come first, before `clang`.
                clang-tools
                coreutils

                # Runtime
                glibc

                # Toolchains
                binutils
                clang
                gcc
              ]);
          };

          riscv64 = pkgsNativeRISCV64.mkShell rec {
            buildInputs = nativeBuildInputs;

            nativeBuildInputs = with pkgsNativeRISCV64; [
              # Tools
              clang-tools

              # Toolchains
              clang

              # Build tools
              cmake
              gnumake
            ];
          };
        };

        formatter = treefmt'.config.build.wrapper;
      }
    );
}
